using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

public class ExpressionQueryBuilder<T> : IQueryBuilder<T>
{
    private readonly StringBuilder _query = new StringBuilder();
    private readonly StringBuilder _select = new StringBuilder();
    private readonly StringBuilder _orderBy = new StringBuilder();
    private readonly StringBuilder _groupBy = new StringBuilder();
    private readonly Dictionary<string, object> _param = new Dictionary<string, object>();
    private readonly Dictionary<string, int> _nameIndexs = new Dictionary<string, int>();
    
    private bool _hasQuery = false;
    private string _tableName;
    private readonly string _safeLeft = "[";
    private readonly string _safeRight = "]";
    private readonly string _preParamName = "@";
    
    // 操作符映射
    private readonly Dictionary<ExpressionType, string> _operators = new Dictionary<ExpressionType, string>
    {
        { ExpressionType.Equal, "=" },
        { ExpressionType.NotEqual, "!=" },
        { ExpressionType.GreaterThan, ">" },
        { ExpressionType.GreaterThanOrEqual, ">=" },
        { ExpressionType.LessThan, "<" },
        { ExpressionType.LessThanOrEqual, "<=" },
        { ExpressionType.AndAlso, " and " },
        { ExpressionType.OrElse, " or " }
    };
    
    public Dictionary<string, object> Param => _param;
    
    public ExpressionQueryBuilder()
    {
        _tableName = typeof(T).Name;
    }
    
    public ExpressionQueryBuilder(string tableName)
    {
        _tableName = tableName;
    }
    
    public IQueryBuilder<T> Where(Expression<Func<T, bool>> exp)
    {
        if (exp == null) return this;
        
        if (_hasQuery)
        {
            _query.Append(" and ");
        }
        else
        {
            _hasQuery = true;
        }
        
        _query.Append("(");
        ParseExpression(exp.Body);
        _query.Append(")");
        
        return this;
    }
    
    public IQueryBuilder<T> OrWhere(Expression<Func<T, bool>> exp)
    {
        if (exp == null) return this;
        
        if (!_hasQuery)
        {
            throw new InvalidOperationException("OrWhere必须跟在已有查询条件后面");
        }
        
        _query.Append(" or (");
        ParseExpression(exp.Body);
        _query.Append(")");
        
        return this;
    }
    
    public IQueryBuilder<T> OrderBy<TResult>(Expression<Func<T, TResult>> exp)
    {
        if (_orderBy.Length > 0) _orderBy.Append(", ");
        _orderBy.Append(GetMemberName(exp));
        return this;
    }
    
    public IQueryBuilder<T> OrderByDescending<TResult>(Expression<Func<T, TResult>> exp)
    {
        if (_orderBy.Length > 0) _orderBy.Append(", ");
        _orderBy.Append($"{GetMemberName(exp)} DESC");
        return this;
    }
    
    public IQueryBuilder<T> GroupBy<TResult>(Expression<Func<T, TResult>> exp)
    {
        if (_groupBy.Length > 0) _groupBy.Append(", ");
        _groupBy.Append(GetMemberName(exp));
        return this;
    }
    
    public IQueryBuilder<T> Select<TResult>(Expression<Func<T, TResult>> exp)
    {
        _select.Clear();
        _select.Append(GetMemberName(exp));
        return this;
    }
    
    public IQueryBuilder<T> SelectCount()
    {
        _select.Clear();
        _select.Append("COUNT(*)");
        return this;
    }
    
    public IQueryBuilder<T> Limit(int count)
    {
        // 实现分页逻辑
        return this;
    }
    
    public IQueryBuilder<T> Skip(int count)
    {
        // 实现跳过逻辑
        return this;
    }
    
    public IQueryBuilder<T> Update<TResult>(Expression<Func<T, TResult>> newExp)
    {
        // 实现更新逻辑
        return this;
    }
    
    public string GetQuery()
    {
        var sql = new StringBuilder();
        
        // SELECT部分
        sql.Append("SELECT ");
        if (_select.Length > 0)
        {
            sql.Append(_select);
        }
        else
        {
            sql.Append("*");
        }
        
        // FROM部分
        sql.Append($" FROM {_safeLeft}{_tableName}{_safeRight}");
        
        // WHERE部分
        if (_hasQuery)
        {
            sql.Append(" WHERE ");
            sql.Append(_query);
        }
        
        // GROUP BY部分
        if (_groupBy.Length > 0)
        {
            sql.Append(" GROUP BY ");
            sql.Append(_groupBy);
        }
        
        // ORDER BY部分
        if (_orderBy.Length > 0)
        {
            sql.Append(" ORDER BY ");
            sql.Append(_orderBy);
        }
        
        return sql.ToString();
    }
    
    public string GetCountQuery()
    {
        var sql = new StringBuilder();
        sql.Append($"SELECT COUNT(*) FROM {_safeLeft}{_tableName}{_safeRight}");
        
        if (_hasQuery)
        {
            sql.Append(" WHERE ");
            sql.Append(_query);
        }
        
        return sql.ToString();
    }
    
    // 核心表达式解析方法
    private void ParseExpression(Expression exp)
    {
        switch (exp.NodeType)
        {
            case ExpressionType.AndAlso:
            case ExpressionType.OrElse:
                ParseBinaryExpression(exp as BinaryExpression);
                break;
            case ExpressionType.Call:
                ParseMethodCall(exp as MethodCallExpression);
                break;
            default:
                ParseComparison(exp as BinaryExpression);
                break;
        }
    }
    
    private void ParseBinaryExpression(BinaryExpression exp)
    {
        var isOr = exp.NodeType == ExpressionType.OrElse;
        
        if (isOr) _query.Append("(");
        ParseExpression(exp.Left);
        _query.Append(_operators[exp.NodeType]);
        ParseExpression(exp.Right);
        if (isOr) _query.Append(")");
    }
    
    private void ParseComparison(BinaryExpression exp)
    {
        // 获取属性名
        string propertyName = GetMemberName(exp.Left);
        
        // 获取值
        object value = GetExpressionValue(exp.Right);
        
        // 处理NULL值
        if (value == null)
        {
            var nullOp = exp.NodeType == ExpressionType.Equal ? "IS NULL" : "IS NOT NULL";
            _query.Append($"{_safeLeft}{propertyName}{_safeRight} {nullOp}");
            return;
        }
        
        // 添加参数
        string paramName = AddParameter(propertyName, value);
        string op = _operators[exp.NodeType];
        
        _query.Append($"{_safeLeft}{propertyName}{_safeRight} {op} {_preParamName}{paramName}");
    }
    
    private void ParseMethodCall(MethodCallExpression exp)
    {
        switch (exp.Method.Name)
        {
            case "Contains":
                ParseContains(exp);
                break;
            case "StartsWith":
                ParseStartsWith(exp);
                break;
            case "EndsWith":
                ParseEndsWith(exp);
                break;
            default:
                throw new NotSupportedException($"不支持的方法: {exp.Method.Name}");
        }
    }
    
    private void ParseContains(MethodCallExpression exp)
    {
        if (exp.Object != null && exp.Object.Type == typeof(string))
        {
            // 字符串Contains -> LIKE
            string propertyName = GetMemberName(exp.Object);
            object value = GetExpressionValue(exp.Arguments[0]);
            string paramName = AddParameter(propertyName, $"%{EscapeLikeValue(value.ToString())}%");
            
            _query.Append($"{_safeLeft}{propertyName}{_safeRight} LIKE {_preParamName}{paramName} ESCAPE '\\'");
        }
        else
        {
            // 集合Contains -> IN
            string propertyName = GetMemberName(exp.Arguments[0]);
            object collection = GetExpressionValue(exp.Object);
            
            if (collection is System.Collections.IEnumerable enumerable)
            {
                var values = enumerable.Cast<object>().ToArray();
                if (values.Length == 0)
                {
                    _query.Append("1=0"); // 空集合
                    return;
                }
                
                if (values.Length == 1)
                {
                    string paramName = AddParameter(propertyName, values[0]);
                    _query.Append($"{_safeLeft}{propertyName}{_safeRight} = {_preParamName}{paramName}");
                    return;
                }
                
                _query.Append($"{_safeLeft}{propertyName}{_safeRight} IN (");
                for (int i = 0; i < values.Length; i++)
                {
                    string paramName = AddParameter($"{propertyName}_{i}", values[i]);
                    _query.Append($"{_preParamName}{paramName}");
                    if (i < values.Length - 1) _query.Append(", ");
                }
                _query.Append(")");
            }
        }
    }
    
    private void ParseStartsWith(MethodCallExpression exp)
    {
        string propertyName = GetMemberName(exp.Object);
        object value = GetExpressionValue(exp.Arguments[0]);
        string paramName = AddParameter(propertyName, $"{EscapeLikeValue(value.ToString())}%");
        
        _query.Append($"{_safeLeft}{propertyName}{_safeRight} LIKE {_preParamName}{paramName} ESCAPE '\\'");
    }
    
    private void ParseEndsWith(MethodCallExpression exp)
    {
        string propertyName = GetMemberName(exp.Object);
        object value = GetExpressionValue(exp.Arguments[0]);
        string paramName = AddParameter(propertyName, $"%{EscapeLikeValue(value.ToString())}");
        
        _query.Append($"{_safeLeft}{propertyName}{_safeRight} LIKE {_preParamName}{paramName} ESCAPE '\\'");
    }
    
    private string GetMemberName(Expression exp)
    {
        if (exp is MemberExpression member)
        {
            return member.Member.Name;
        }
        
        if (exp is UnaryExpression unary && unary.Operand is MemberExpression unaryMember)
        {
            return unaryMember.Member.Name;
        }
        
        throw new ArgumentException($"无法获取成员名称: {exp}");
    }
    
    private object GetExpressionValue(Expression exp)
    {
        if (exp is ConstantExpression constant)
        {
            return constant.Value;
        }
        
        // 编译并执行表达式
        return Expression.Lambda(exp).Compile().DynamicInvoke();
    }
    
    private string AddParameter(string name, object value)
    {
        string paramName = name;
        
        if (_param.ContainsKey(paramName))
        {
            if (!_nameIndexs.ContainsKey(name))
                _nameIndexs[name] = 1;
            
            _nameIndexs[name]++;
            paramName = $"{name}{_nameIndexs[name]}";
        }
        
        _param.Add(paramName, value);
        return paramName;
    }
    
    private string EscapeLikeValue(string value)
    {
        return value.Replace("'", "''").Replace("[", "\\[")
                   .Replace("]", "\\]").Replace("%", "\\%")
                   .Replace("_", "\\_");
    }
}